Trò chơi Tic-Tac-Toe, game đánh caro full source code
- PickupItem.cs
- UtilityScripts /
- Photon Unity Networking /
- Assets /
- project /
2 using UnityEngine;
3 using System.Collections;
4 using Hashtable = ExitGames.Client.Photon.Hashtable;
5
6
7 /// <summary>
8 /// Makes a scene object pickup-able. Needs a PhotonView which belongs to the scene.
9 /// </summary>
10 /// <remarks>Includes a OnPhotonSerializeView implementation that </remarks>
11 [RequireComponent(typeof(PhotonView))]
12 public class PickupItem : Photon.MonoBehaviour, IPunObservable
13 {
14 ///<summary>Enables you to define a timeout when the picked up item should re-spawn at the same place it was before.</summary>
15 /// <remarks>
16 /// Set in Inspector per GameObject! The value in code is just the default.
17 ///
18 /// If you don't want an item to respawn, set SecondsBeforeRespawn == 0.
19 /// If an item does not respawn, it could be consumed or carried around and dropped somewhere else.
20 ///
21 /// A respawning item should stick to a fixed position. It should not be observed at all (in any PhotonView).
22 /// It can only be consumed and can't be dropped somewhere else (cause that would double the item).
23 ///
24 /// This script uses PunRespawn() as RPC and as method that gets called by Invoke() after a timeout.
25 /// No matter if the item respawns timed or by Drop, that method makes sure (temporary) owner and other status-values
26 /// are being re-set.
27 /// </remarks>
28 public float SecondsBeforeRespawn = 2;
29
30 /// <summary>The most likely trigger to pick up an item. Set in inspector!</summary>
31 /// <remarks>Edit the collider and set collision masks to avoid pickups by random objects.</remarks>
32 public bool PickupOnTrigger;
33
34 /// <summary>If the pickup item is currently yours. Interesting in OnPickedUp(PickupItem item).</summary>
35 public bool PickupIsMine;
36
37 /// <summary>GameObject to send an event "OnPickedUp(PickupItem item)" to.</summary>
38 /// <remarks>
39 /// Implement OnPickedUp(PickupItem item) {} in some script on the linked game object.
40 /// The item will be "this" and item.PickupIsMine will help you to find if this pickup was done by "this player".
41 /// </remarks>
42 public MonoBehaviour OnPickedUpCall;
43
44
45 // these values are internally used. they are public for debugging only
46
47 /// <summary>If this client sent a pickup. To avoid sending multiple pickup requests before reply is there.</summary>
48 public bool SentPickup;
49
50 /// <summary>Timestamp when to respawn the item (compared to PhotonNetwork.time). </summary>
51 public double TimeOfRespawn; // needed when we want to update new players when a PickupItem respawns
52
53 /// <summary></summary>
54 public int ViewID { get { return this.photonView.viewID; } }
55
56 public static HashSet<PickupItem> DisabledPickupItems = new HashSet<PickupItem>();
57
58
59 public void OnTriggerEnter(Collider other)
60 {
61 // we only call Pickup() if "our" character collides with this PickupItem.
62 // note: if you "position" remote characters by setting their translation, triggers won't be hit.
63
64 PhotonView otherpv = other.GetComponent<PhotonView>();
65 if (this.PickupOnTrigger && otherpv != null && otherpv.isMine)
66 {
67 //Debug.Log("OnTriggerEnter() calls Pickup().");
68 this.Pickup();
69 }
70 }
71
72
73
74 public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
75 {
76 // read the description in SecondsBeforeRespawn
77
78 if (stream.isWriting && SecondsBeforeRespawn <= 0)
79 {
80 stream.SendNext(this.gameObject.transform.position);
81 }
82 else
83 {
84 // this will directly apply the last received position for this PickupItem. No smoothing. Usually not needed though.
85 Vector3 lastIncomingPos = (Vector3)stream.ReceiveNext();
86 this.gameObject.transform.position = lastIncomingPos;
87 }
88 }
89
90
91 public void Pickup()
92 {
93 if (this.SentPickup)
94 {
95 // skip sending more pickups until the original pickup-RPC got back to this client
96 return;
97 }
98
99 this.SentPickup = true;
100 this.photonView.RPC("PunPickup", PhotonTargets.AllViaServer);
101 }
102
103
104 /// <summary>Makes use of RPC PunRespawn to drop an item (sent through server for all).</summary>
105 public void Drop()
106 {
107 if (this.PickupIsMine)
108 {
109 this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer);
110 }
111 }
112
113 /// <summary>Makes use of RPC PunRespawn to drop an item (sent through server for all).</summary>
114 public void Drop(Vector3 newPosition)
115 {
116 if (this.PickupIsMine)
117 {
118 this.photonView.RPC("PunRespawn", PhotonTargets.AllViaServer, newPosition);
119 }
120 }
121
122
123 [RPC]
124 public void PunPickup(PhotonMessageInfo msgInfo)
125 {
126 // when this client's RPC gets executed, this client no longer waits for a sent pickup and can try again
127 if (msgInfo.sender.isLocal) this.SentPickup = false;
128
129
130 // In this solution, picked up items are disabled. They can't be picked up again this way, etc.
131 // You could check "active" first, if you're not interested in failed pickup-attempts.
132 if (!this.gameObject.GetActive())
133 {
134 // optional logging:
135 Debug.Log("Ignored PU RPC, cause item is inactive. " + this.gameObject + " SecondsBeforeRespawn: " + SecondsBeforeRespawn + " TimeOfRespawn: " + this.TimeOfRespawn + " respawn in future: " + (TimeOfRespawn > PhotonNetwork.time));
136 return; // makes this RPC being ignored
137 }
138
139
140 // if the RPC isn't ignored by now, this is a successful pickup. this might be "my" pickup and we should do a callback
141 this.PickupIsMine = msgInfo.sender.isLocal;
142
143 // call the method OnPickedUp(PickupItem item) if a GameObject was defined as callback target
144 if (this.OnPickedUpCall != null)
145 {
146 // you could also skip callbacks for items that are not picked up by this client by using: if (this.PickupIsMine)
147 this.OnPickedUpCall.SendMessage("OnPickedUp", this);
148 }
149
150
151 // setup a respawn (or none, if the item has to be dropped)
152 if (SecondsBeforeRespawn <= 0)
153 {
154 this.PickedUp(0.0f); // item doesn't auto-respawn. must be dropped
155 }
156 else
157 {
158 // how long it is until this item respanws, depends on the pickup time and the respawn time
159 double timeSinceRpcCall = (PhotonNetwork.time - msgInfo.timestamp);
160 double timeUntilRespawn = SecondsBeforeRespawn - timeSinceRpcCall;
161
162 //Debug.Log("msg timestamp: " + msgInfo.timestamp + " time until respawn: " + timeUntilRespawn);
163
164 if (timeUntilRespawn > 0)
165 {
166 this.PickedUp((float)timeUntilRespawn);
167 }
168 }
169 }
170
171 internal void PickedUp(float timeUntilRespawn)
172 {
173 // this script simply disables the GO for a while until it respawns.
174 this.gameObject.SetActive(false);
175 PickupItem.DisabledPickupItems.Add(this);
176 this.TimeOfRespawn = 0;
177
178 if (timeUntilRespawn > 0)
179 {
180 this.TimeOfRespawn = PhotonNetwork.time + timeUntilRespawn;
181 Invoke("PunRespawn", timeUntilRespawn);
182 }
183 }
184
185
186 [RPC]
187 internal void PunRespawn(Vector3 pos)
188 {
189 Debug.Log("PunRespawn with Position.");
190 this.PunRespawn();
191 this.gameObject.transform.position = pos;
192 }
193
194 [RPC]
195 internal void PunRespawn()
196 {
197 #if DEBUG
198 // debugging: in some cases, the respawn is "late". it's unclear why! just be aware of this.
199 double timeDiffToRespawnTime = PhotonNetwork.time - this.TimeOfRespawn;
200 if (timeDiffToRespawnTime > 0.1f) Debug.LogWarning("Spawn time is wrong by: " + timeDiffToRespawnTime + " (this is not an error. you just need to be aware of this.)");
201 #endif
202
203
204 // if this is called from another thread, we might want to do this in OnEnable() instead of here (depends on Invoke's implementation)
205 PickupItem.DisabledPickupItems.Remove(this);
206 this.TimeOfRespawn = 0;
207 this.PickupIsMine = false;
208
209 if (this.gameObject != null)
210 {
211 this.gameObject.SetActive(true);
212 }
213 }
214 }
Makes a scene object pickup-able. Needs a PhotonView which belongs to the scene.
Set in Inspector per GameObject! The value in code is just the default.
If you don't want an item to respawn, set SecondsBeforeRespawn == 0.
If an item does not respawn, it could be consumed or carried around and dropped somewhere else.
A respawning item should stick to a fixed position. It should not be observed at all (in any PhotonView).
It can only be consumed and can't be dropped somewhere else (cause that would double the item).
This script uses PunRespawn() as RPC and as method that gets called by Invoke() after a timeout.
No matter if the item respawns timed or by Drop, that method makes sure (temporary) owner and other status-values
are being re-set.
Implement OnPickedUp(PickupItem item) {} in some script on the linked game object.
The item will be "this" and item.PickupIsMine will help you to find if this pickup was done by "this player".
these values are internally used. they are public for debugging only
public double TimeOfRespawn; needed when we want to update new players when a PickupItem respawns
we only call Pickup() if "our" character collides with this PickupItem.
note: if you "position" remote characters by setting their translation, triggers won't be hit.
Debug.Log("OnTriggerEnter() calls Pickup().");
read the description in SecondsBeforeRespawn
this will directly apply the last received position for this PickupItem. No smoothing. Usually not needed though.
skip sending more pickups until the original pickup-RPC got back to this client
when this client's RPC gets executed, this client no longer waits for a sent pickup and can try again
In this solution, picked up items are disabled. They can't be picked up again this way, etc.
You could check "active" first, if you're not interested in failed pickup-attempts.
optional logging:
return; makes this RPC being ignored
if the RPC isn't ignored by now, this is a successful pickup. this might be "my" pickup and we should do a callback
call the method OnPickedUp(PickupItem item) if a GameObject was defined as callback target
you could also skip callbacks for items that are not picked up by this client by using: if (this.PickupIsMine)
setup a respawn (or none, if the item has to be dropped)
this.PickedUp(0.0f); item doesn't auto-respawn. must be dropped
how long it is until this item respanws, depends on the pickup time and the respawn time
Debug.Log("msg timestamp: " + msgInfo.timestamp + " time until respawn: " + timeUntilRespawn);
this script simply disables the GO for a while until it respawns.
debugging: in some cases, the respawn is "late". it's unclear why! just be aware of this.
if this is called from another thread, we might want to do this in OnEnable() instead of here (depends on Invoke's implementation)